package site.lianwu.mybatis.plus.query.processor;

import site.lianwu.mybatis.plus.query.model.ExecutableQueryStatement;
import site.lianwu.mybatis.plus.query.model.QueryClass;
import site.lianwu.mybatis.plus.query.model.QueryField;
import site.lianwu.mybatis.plus.query.reflection.FieldGetters;
import site.lianwu.mybatis.plus.query.reflection.Reflections;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 常规查询类处理器
 *
 * @author LianWu
 */
public class GeneralQueryClassProcessor extends BaseQueryClassProcessor {

    public GeneralQueryClassProcessor() {
        this(new ArrayList<>(2));
        queryFieldProcessors.add(new GeneralQueryFieldProcessor());
        queryFieldProcessors.add(new NestedQueryFieldProcessor(this));
    }

    public GeneralQueryClassProcessor(Collection<QueryFieldProcessor> queryFieldProcessors) {
        super(queryFieldProcessors);
    }

    /**
     * 提取查询类
     * <br>
     * 遍历条件对象所属类的所有字段，委托查询字段处理器提取查询字段，并将结果封装在查询类
     *
     * @param clz 条件对象所属类
     * @param includeInheritedFields 是否包含继承字段
     * @return 查询类 {@link QueryClass}
     */
    @Override
    public QueryClass extract(Class<?> clz, boolean includeInheritedFields) {
        List<Field> declaredFields = FieldGetters.getAllFields(clz, includeInheritedFields);
        List<QueryField> queryFields = new ArrayList<>();
        declaredFields.forEach(field ->
                queryFieldProcessors.forEach(fieldProcessor -> fieldProcessor.extract(field).ifPresent(queryFields::add))
        );
        return new QueryClass(clz, includeInheritedFields, queryFields);
    }

    /**
     * 解析查询类
     * <br>
     * 遍历查询类的所有查询字段，委托查询字段处理器解析查询字段，生成可执行的查询语句列表
     *
     * @param queryClass 查询类
     * @param obj 条件对象
     * @return 可执行的查询语句 {@link ExecutableQueryStatement}列表
     */
    @Override
    public List<ExecutableQueryStatement> parse(QueryClass queryClass, Object obj) {
        List<QueryField> queryFields = queryClass.getQueryFields();
        List<ExecutableQueryStatement> executableQueryStatements = new ArrayList<>(queryFields.size());
        queryFields.forEach(queryField -> {
            Object fieldValue = Reflections.getFieldValue(queryField.getField(), obj);
            queryFieldProcessors.forEach(processor -> executableQueryStatements.addAll(processor.parse(queryField, fieldValue)));
        });
        return executableQueryStatements;
    }

}
